package com.huang.slideswitch.SlideSwitchView;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.huang.slideswitch.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;


/**
 * 作者： huangRZ  日期： 2017/4/11. email：huangrz11@163.com
 * Explain：自定义开关
 */

public class SlideSwitch extends View {

    //可自定义属性
    private int block_color = Color.WHITE; //默认滑动块为白色
    private int open_color = 0xFF08C130;   //默认打开时背景颜色为青色
    private int close_color = Color.GRAY;  //默认关闭时背景颜色为深灰色
    private int shape = CIRCLE;   //背景形状默认为矩形
    private boolean isOpen = false; //默认为关闭的状态
    private int mode = DRAG_MODE; //模式，拖拽或者点击

    private int with;
    private int height;

    private int rim_size = 6;  //默认滑动块与边框的距离为6个像素
    private int alpha = isOpen ? 255 : 0;
    private Paint open_paint;
    private Paint close_paint;
    private Rect rect;
    private Rect block;
    private Paint block_paint;
    private RectF rectF;

    private int slide_distance; //滑块的滑动距离
    private int block_left;
    private int block_right;
    private float currentX;
    private int slide_range; //滑动块可移动的范围
    private float startX;

    private static final int DRAG_MODE = 3;
    private static final int CLICK_MODE = 4;
    @IntDef(value = {DRAG_MODE, CLICK_MODE})
    @Retention(RetentionPolicy.SOURCE)
    private @interface Mode{
    }

    public static final int RECT = 1;
    public static final int CIRCLE = 2;
    @IntDef(value = {RECT, CIRCLE})
    @Retention(RetentionPolicy.SOURCE)
    private @interface Shape{
    }

    public SlideSwitch(Context context) {
        super(context);

        init(context);
    }

    public SlideSwitch(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SlideSwitch);
        block_color = typedArray.getColor(R.styleable.SlideSwitch_block_color, block_color);
        open_color = typedArray.getColor(R.styleable.SlideSwitch_open_color, open_color);
        close_color = typedArray.getColor(R.styleable.SlideSwitch_close_color, close_color);
        shape = typedArray.getInt(R.styleable.SlideSwitch_shape, shape);
        mode = typedArray.getInt(R.styleable.SlideSwitch_mode, mode);
        isOpen = typedArray.getBoolean(R.styleable.SlideSwitch_isOpen, isOpen);
        typedArray.recycle();

        init(context);
    }

    public SlideSwitch(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init(Context context) {
        //开启时，背景的画笔
        open_paint = new Paint();
        open_paint.setAntiAlias(true); //去除锯齿
        open_paint.setColor(open_color);

        //关闭时，背景的画笔
        close_paint = new Paint();
        close_paint.setAntiAlias(true);
        close_paint.setColor(close_color);

        //滑动块
        block_paint = new Paint();
        block_paint.setColor(block_color);
        block_paint.setAntiAlias(true);
        block = new Rect();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int withSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        if (withSpecMode == MeasureSpec.AT_MOST){
            //如果选择包裹模式，则设置默认宽度50dp
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(dip2px(getContext(), 50), withSpecMode);
        }
        if (heightSpecMode == MeasureSpec.AT_MOST){
            //如果选择包裹模式，则设置默认高度20dp
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(dip2px(getContext(), 20), heightSpecMode);
        }
        //如果是其他模式，执行父类方法测量控件
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    public int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    //根据测量的值返回不同的结果值
    private int measureDimension(int defaultSize, int measureSpec) {
        int result = defaultSize; //UNSPECIFIED
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        Log.e("tag", "measureDimension: specSize : " + specSize);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
        return result;
    }

    //在onMeasure执行完后，执行该方法，一般在这里初始化一些需要控件长宽等数值的参数
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        setPadding(0, 0, 0, 0);  //只允许padding为0
        with = getMeasuredWidth();
        height = getMeasuredHeight();
        Log.e("tag", "onSizeChanged: with : " + with + "  height : " + height );

        //画背景区域
        rect = new Rect(0, 0, with, height);
        rectF = new RectF(0, 0, with, height);

        //边界
        block_left = getLeft() + rim_size; //滑动块左边界
        block_right = getRight() - height + rim_size;//滑块的左边界
        slide_range = block_right - block_left;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        open_paint.setAlpha(alpha);
        if (shape == RECT) {
            canvas.drawRect(rect, close_paint);
            canvas.drawRect(rect, open_paint);
            block.set(rim_size + slide_distance, rim_size, height - rim_size + slide_distance, height - rim_size);
            canvas.drawRect(block, block_paint);
        } else {
            int radius = height / 2;
            canvas.drawRoundRect(rectF, radius, radius, close_paint);
            canvas.drawRoundRect(rectF, radius, radius, open_paint);
            canvas.drawCircle(radius + slide_distance, radius, radius - rim_size, block_paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //如果当前是点击模式，则不考虑滑动事件
        if (mode == CLICK_MODE) {
            setOpen(!isOpen);//只要控件被点击，就切换开关状态
            return super.onTouchEvent(event);
        }
        // 通知父控件勿拦截本控件touch事件
        getParent().requestDisallowInterceptTouchEvent(true);
        switch (MotionEventCompat.getActionMasked(event)) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getRawX();
                break;
            case MotionEvent.ACTION_MOVE:
                //判断滑动块是否被点击，是则可以进行拖拽，不是则不处理
                if ((!isOpen && startX < block_left + height - 2*rim_size) || (isOpen && startX > block_right)) {
                    currentX = event.getRawX();
                    if (currentX < block_left + height / 2 - rim_size) {
                        slide_distance = 0;
                        alpha = 0;
                    } else if (currentX > block_right + height / 2 - rim_size) {
                        slide_distance = slide_range;
                        alpha = 255;
                    } else {
                        slide_distance = (int) (currentX - height / 2 + rim_size - block_left);
                        alpha = 255 * slide_distance / slide_range;
                    }
                    invalidateView();
                }
                break;
            case MotionEvent.ACTION_UP:
                setOpen(!(event.getRawX() < getLeft() + with / 2)); //判断手指抬起时，在控件的左边还是右边，直接切换状态
                break;
        }
        return true;
    }

    /**
     * 刷新控件，重新绘制
     */
    private void invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            invalidate(); //主线程绘制（同步）
        } else {
            postInvalidate();  //其他线程绘制（异步）
        }
    }

    /**
     * 设置模式
     *  CLICK_MODE ：点击模式，只要控件被点击就会切换状态
     *  DRAG_MODE ：拖拽模式，点击滑动块，滑动块可以被拖拽，点击不是滑动块的区域，直接切换状态
     *
     * @param mode 模式
     */
    private void setMode(@Mode int mode){
        this.mode = mode;
    }

    /**
     * 设置控件形状
     *  RECT : 矩形
     *  CIRCLE : 圆形
     *
     * @param shape 形状
     */
    private void setShape(@Shape int shape){
        this.shape = shape;
    }

    /**
     * 获取控件当前的打开状态
     *
     * @return TRUE：控件为打开状态   FALSE：控件为关闭状态
     */
    public boolean isOpen() {
        return isOpen;
    }

    /**
     * 设置开关的打开状态
     *
     * @param open 打开状态 TRUE：打开   FALSE：关闭
     */
    public void setOpen(boolean open) {
        this.isOpen = open;
        moveToTarget(open);
    }

    /**
     * 将滑动块移动到指定的位置
     *
     * @param isOpen 控件的打开状态
     */
    private void moveToTarget(final boolean isOpen) {
        //属性动画 - 数值动画
        ValueAnimator valueAnimator = ValueAnimator.ofInt(slide_distance, isOpen ? slide_range : 0);
        valueAnimator.setDuration(200);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                slide_distance = (int) animation.getAnimatedValue();
                alpha = 255 * slide_distance / slide_range;
                invalidateView();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (isOpen) {
                    if (listener != null)
                        listener.onOpen();
                } else {
                    if (listener != null)
                        listener.onClose();
                }
            }
        });
        valueAnimator.start();
    }

    /**
     * 设置控件状态监听器
     *
     * @param listener 监听器
     */
    public void setOnStateListener(OnStateListener listener) {
        this.listener = listener;
    }

    private OnStateListener listener;

    //监听器接口
    public interface OnStateListener {
        void onClose();

        void onOpen();
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            this.isOpen = bundle.getBoolean("isOpen");
            state = bundle.getParcelable("instanceState");
        }
        super.onRestoreInstanceState(state);
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable("instanceState", super.onSaveInstanceState());
        bundle.putBoolean("isOpen", this.isOpen);
        return bundle;
    }
}
